package com.fount4j.generator.introspect;

import com.fount4j.generator.config.TableConfig;
import com.fount4j.generator.constant.GeneratorConstants;
import com.fount4j.generator.context.GeneratorContext;
import com.fount4j.generator.exception.GenerateException;
import com.fount4j.generator.jdbc.ConnectionFactory;
import com.fount4j.generator.util.JdbcUtils;
import org.apache.commons.io.FileUtils;
import org.beetl.core.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.List;

/**
 * 生成器主类
 *
 * @author Morven 2016/12/20
 */
public class Generator {
    private Logger logger = LoggerFactory.getLogger(Generator.class);
    /** 生成器上下文 */
    protected GeneratorContext context;

    public Generator(GeneratorContext context) {
        this.context = context;
    }

    public void generate() {
        List<TableConfig> tables = context.getTables();
        if (tables == null || tables.isEmpty()) {
            logger.warn("没有配置要生成的表");
            return;
        }

        Connection con = null;
        try {
            con = getConnection();
            DatabaseMetaData metaData = con.getMetaData();
            for (TableConfig tableConfig : tables) {
                context.setTableConfig(tableConfig);
                context.getIntrospector().introspectTable(context, metaData);
                generateFiles();
            }
        } catch (SQLException e) {
            throw new GenerateException("获取数据库元数据出错", e);
        } finally {
            JdbcUtils.close(con);
        }
    }

    protected void generateFiles() {
        generateEntityFile();
        generateDaoFile();
        generateMapperFile();
    }

    protected void generateMapperFile() {
        if (!context.getMapperConfig().isEnable()) {
            logger.info("已配置不生成映射文件");
            return;
        }
        Template mapperTemplate = context.getMapperTemplate();
        mapperTemplate.binding("table", context.getTableInfo());
        mapperTemplate.binding("entity", context.getEntityInfo());
        mapperTemplate.binding("dao", context.getDaoInfo());
        mapperTemplate.binding("mapper", context.getMapperInfo());
        String mapperContent = mapperTemplate.render();
        try {
            FileUtils.writeStringToFile(context.getMapperInfo().getFile(), mapperContent,
                    GeneratorConstants.GLOBAL_ENCODING);
        } catch (IOException e) {
            throw new GenerateException("生成映射文件出错", e);
        }
    }

    protected void generateDaoFile() {
        if (!context.getDaoConfig().isEnable()) {
            logger.info("已配置不生成 Dao 类");
            return;
        }
        Template daoTemplate = context.getDaoTemplate();
        daoTemplate.binding("table", context.getTableInfo());
        daoTemplate.binding("entity", context.getEntityInfo());
        daoTemplate.binding("dao", context.getDaoInfo());
        String daoContent = daoTemplate.render();
        try {
            FileUtils.writeStringToFile(context.getDaoInfo().getFile(), daoContent, GeneratorConstants.GLOBAL_ENCODING);
        } catch (IOException e) {
            throw new GenerateException("生成 Dao 类文件出错", e);
        }
    }

    protected void generateEntityFile() {
        if (!context.getEntityConfig().isEnable()) {
            logger.info("已配置不生成实体类");
            return;
        }
        Template entityTemplate = context.getEntityTemplate();
        entityTemplate.binding("table", context.getTableInfo());
        entityTemplate.binding("entity", context.getEntityInfo());
        String entityContent = entityTemplate.render();
        try {
            FileUtils.writeStringToFile(context.getEntityInfo().getFile(), entityContent,
                    GeneratorConstants.GLOBAL_ENCODING);
        } catch (IOException e) {
            throw new GenerateException("生成实体类文件出错", e);
        }
    }

    /**
     * 获取数据库连接
     *
     * @return 数据库 JDBC 连接
     */
    protected Connection getConnection() {
        ConnectionFactory connectionFactory = context.getConnectionFactory();
        if (connectionFactory == null) {
            throw new GenerateException("没有配置数据库连接");
        }
        return connectionFactory.getConnection();
    }

}
